每天的專案會同步到 GitLab 上,可以前往 GitLab 查看,有興趣的朋友歡迎留言 or 來信討論,我的信箱是 nickchen1998@gmail.com。
由於時間關係,本次專案不考慮系統架構,僅止於快速實作出站台功能。
今天我們要介紹的是問題及解答重構,並且把它串接近爬文流程當中。
在前面的章節有提到,過於冗長的文本在計算 embedding 時會比較不精準,且不利於查詢,尤其是患者在描述自己症狀的時候,常常會過於冗長,這時候就需要將問題及解答進行重構,讓它更加精簡,這樣在進行 embedding 時,就能夠更加精準地找到相似的問題及解答。
在本次的系統設計當中,我們主要會用使用者輸入的問題,去查出相近的問題,並且取得這個問題對應的醫生建議,然後將原始問題一併送交給 LLM 進行回答。
這邊先快速介紹一下專案架構:
前面提到,我們會針對使用者的問題進行搜尋而不是回答,因此回答的重構目標主要是將內容進行精簡,盡可能減少冗言贅字,避免將參考資料送給 LLM 的時候會產生過多的雜訊。
根據上面的目標,讓我們看一下下面這個 function:
from langchain_core.prompts import ChatPromptTemplate
def get_refactor_answer(paragraph: str):
prompt = ChatPromptTemplate.from_template(
"""
你是一個專業的醫生,下面是一篇醫生針對某個患者描述的情況的回應,請幫我使用繁體中文做重點整理,讓患者可以更清楚狀況。
請針對我給予的文章做回覆整理,不要使用文章以外的內容做回覆。
----
文章: {paragraph}
"""
)
chain = prompt | get_llm()
return chain.invoke({"paragraph": paragraph}).content
可以看到我在 prompt 當中沒有做過多的限制,只有限制使用的語言以及不要使用文章以外的內容做回覆。
在程式碼當中可以看到一個 get_llm 的函式,這個主要是用來建立一個 LangChain 的物件,讓我們可以輕易的調用 OpenAI 來進行問答,可以參考下面這段程式碼:
from langchain_openai import ChatOpenAI
from env_settings import EnvSettings
def get_llm():
env_settings = EnvSettings()
return ChatOpenAI(
api_key=env_settings.OPENAI_API_KEY,
model_name="gpt-4o"
)
讓我們看一下重構前後的內容對比:
before
after
可以看得出來在重構後的內容中,已經將冗言贅字去除,讓醫生的建議更佳精簡。
由於我們是要使用者輸入的問題去查找相似的問題,因此問題的重構也是非常重要的一環,讓我們看一下下面這個 function:
from langchain_core.prompts import ChatPromptTemplate
def get_refactor_question(paragraph: str):
prompt = ChatPromptTemplate.from_template(
"""
你是一個要去診所進行看診的換診,下面是你的問題,請幫我是用繁體中文做重點整理,讓醫生可以更清楚你的症狀。
過程中請不要針對我的病況給予我任何建議,請幫我整理問題就好,並且不要使用文章以外的內容。
我希望可以把內容縮減在 100 字以內,並且使用簡答的方式整理成一句話,並且不要列點。
請直接給我回覆,不需要給予開頭或結尾。
----
文章: {paragraph}
"""
)
chain = prompt | get_llm()
return chain.invoke({"paragraph": paragraph}).content
可以看到相比於回答的重構,問題的重構多了一些限制,例如不要使用文章以外的內容,並且要縮減在 100 字以內,並且使用簡答的方式整理成一句話,且不要列點。
我們馬上來看一下對比:
before
after
可以看到我們成功地將問題進行了重構,讓問題更加精簡,這樣在進行 embedding 的時候,就能夠更加精準地找到相似的問題。
前面有提到,由於時間的關係,不考慮執行時間、效率等其他因素,因此我們這邊直接將剛剛兩個 function 串接進爬文流程當中,讓我們看一下下面這段程式碼:
from llms import get_refactor_answer, get_refactor_question
...
data = dict(
category=category,
subject=subject,
question=question,
gender=gender,
question_time=question_time,
answer=answer,
doctor_name=doctor_name,
doctor_department=doctor_department,
answer_time=answer_time,
view_amount=view_amount,
refactor_question=get_refactor_question(question),
refactor_answer=get_refactor_answer(answer)
)
...
我們直接在昨天的 data 這個區塊裡面加入兩個 key,而 value 的部分則是使用剛剛的兩個 function 進行轉換,這樣就完成了問題及解答的重構。
今天我們完成了將問題及回覆的重構,明天我們要來把問題計算成向量,並且將所有的資料插入到 MongoDB 當中。